package com.treasure.service.task.service.impl;

import com.treasure.service.domain.TaskSchedulerJob;
import com.treasure.service.mapper.TaskSchedulerJobMapper;
import org.quartz.*;
import org.quartz.core.jmx.JobDataMapSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2017/4/10.
 */
@DisallowConcurrentExecution
@Service("quartzJobFactory")
public class QuartzJobFactory {

    @Autowired
    private TaskSchedulerJobMapper taskSchedulerJobMapper;
    @Autowired
    private Scheduler scheduler;
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    /**
     * @Note : 扫面数据库,查看是否有计划任务的变动
     */
    public void initScheduleJob() {
        try {
            List<TaskSchedulerJob> jobList = taskSchedulerJobMapper.selectAll();
            if (jobList.size() != 0) {
                for (TaskSchedulerJob job : jobList) {
                    createSheduler(job);
                }
            }
        } catch (Exception e) {
            logger.error("初始化定时任务失败 arrageScheduleJob error:{}",e.getMessage());
            e.printStackTrace();
        }
    }

    public void createSheduler(TaskSchedulerJob job ){
        // 不存在，创建一个
        try {
            // Keys are composed of both a name and group, and the name  must be unique within the group
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            // 获取trigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (null == trigger) {
                createSheduler(scheduler, job);
            } else {// Trigger已存在，那么更新相应的定时设置
                updateScheduler(scheduler, job, triggerKey, trigger);
            }
        }catch (Exception e){
            logger.error("初始化定时任务失败createSheduler  jobName: {} jobGroup :{} error:{}",job.getJobName(), job.getJobGroup(),e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 更新相应的定时设置 根据job_status做相应的处理
     *
     * @param scheduler
     * @param job
     * @param triggerKey
     * @param trigger
     * @throws SchedulerException
     */
    private void updateScheduler(Scheduler scheduler, TaskSchedulerJob job, TriggerKey triggerKey, CronTrigger trigger)
        throws SchedulerException {
        if (job.getStatus().equals("1")) {// 0禁用 1启用
            if (!trigger.getCronExpression().equalsIgnoreCase(job.getCronExpression())) {
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
                logger.info(job.getJobGroup() + "." + job.getJobName() + " 更新完毕,目前cron表达式为:" + job.getCronExpression()
                    + "  concurrent: " + job.getJobConcurrent());
            }
        } else if (job.getStatus().equals("0")) {
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            scheduler.deleteJob(trigger.getJobKey());// 删除任务
            logger.info(job.getJobGroup() + "." + job.getJobName() + "删除完毕");
        }

    }

    /**
     * 创建一个定时任务，并做安排
     *
     * @param scheduler
     * @param job
     * @throws SchedulerException
     * @throws Exception
     */
    public void createSheduler(Scheduler scheduler, TaskSchedulerJob job) throws Exception {
        // 在工作状态可用时,即job_status = 1 ,开始创建
        if (job.getStatus().equals("1")) {
            JobDetail jobDetail =  convert2QuartzJobDetail(job,null);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(job.getJobName(), job.getJobGroup())
                .withSchedule(scheduleBuilder)
                .withDescription(df.format( new Date()))
                .build();
            scheduler.scheduleJob(jobDetail, trigger);// 注入到管理类
            logger.info(job.getJobGroup() + "." + job.getJobName() + "创建完毕");
        }
    }


    public JobDetail convert2QuartzJobDetail(TaskSchedulerJob job,Map<String,Object> extInfo)throws Exception{
        Class<? extends Job> clazz = null;
        try {
            clazz = (Class<Job>) ClassUtils.resolveClassName(job.getClazz(), this.getClass().getClassLoader());
        } catch (IllegalArgumentException e) {
            logger.error("加载类错误",e);
            throw new Exception(e);
        }
        return JobBuilder.newJob()
            .ofType(clazz)
            .withIdentity(job.getJobName(),job.getJobGroup())
            .withDescription(job.getDescription())
            .setJobData(JobDataMapSupport.newJobDataMap(extInfo))
            .build();
    }

}
